package com.spa.domain.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.spa.application.config.massagist.ProfitRule;
import com.spa.domain.entity.*;
import com.spa.infrastructure.common.KeyConstant;
import com.spa.infrastructure.enums.dict.SourceEnum;
import com.spa.infrastructure.enums.dict.rule.RuleClassifyEnum;
import com.spa.infrastructure.enums.dict.rule.RuleFlagEnum;
import com.spa.infrastructure.repository.condition.ProfitCondition;
import com.spa.infrastructure.repository.condition.RuleCondition;
import com.spa.infrastructure.repository.po.ProfitPO;
import com.spa.infrastructure.repository.service.ProfitRepositoryService;
import com.spa.infrastructure.repository.service.SysConfigurationRepositoryService;
import com.spa.infrastructure.util.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProfitService {

    @Autowired
    private ProfitRepositoryService profitRepositoryService;

    @Autowired
    private OrderService orderService;

    @Resource
    private RuleService ruleService;

    @Autowired
    private SysConfigurationRepositoryService sysConfigurationRepositoryService;

    /**
     * 订单完成计算收入
     *
     * @param orderId
     */
    public void orderCompletion(Long orderId) {
        OrderService.OrderInfoPlug plug = OrderService.OrderInfoPlug.base();
        plug.setTicket(true);
        OrderInfo orderInfo = orderService.getOrderInfoById(orderId, plug);

        //2024-04-07 需求变动不需要校验是否配置了规则，按照兜底规则计算   edit lig
        addMassagistRuleProfit(orderInfo);

    }

    /**
     * 技师已出发或已到达 用户取消订单
     * 技师联系不上用户 取消订单
     * 将车费分润给技师
     */
    public void addTravelPrice(long shopId, long massagistId, long orderId, int travelPrice) {
        ProfitPO po = new ProfitPO();
        po.setShopId(shopId);
        po.setMassagistId(massagistId);
        po.setOrderId(orderId);
        po.setTravelPrice(travelPrice);
        po.setOrderType(3);
        po.setCreateBy(SessionUtil.getUser().getExtUserId());
        po.setAdminIncome(0);
        po.setShopIncome(0);
        po.setMassagistIncome(0);
        po.setRuleData("{}");
        profitRepositoryService.add(po);
    }

    /**
     * 技师已接单、已出发或已到达 用户取消订单
     * 扣除部分用费给平台
     */
    public void addCancelFee4Admin(long shopId, long massagistId, long orderId, int adminIncome) {
        ProfitPO po = new ProfitPO();
        po.setShopId(shopId);
        po.setMassagistId(massagistId);
        po.setOrderId(orderId);
        po.setTravelPrice(0);
        po.setOrderType(4);
        po.setCreateBy(SessionUtil.getUser().getExtUserId());
        po.setAdminIncome(adminIncome);
        po.setShopIncome(0);
        po.setMassagistIncome(0);
        po.setRuleData("{}");
        profitRepositoryService.add(po);
    }

    /**
     * 技师 指定时间区间内的分润记录
     *
     * @param massagstiId
     * @param beginDate
     * @param endDate
     * @return
     */
    public List<Profit> queryProfitByMassagistId(Long massagstiId, String beginDate, String endDate) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setMassagistId(massagstiId);
        profitCondition.setBeginDate(beginDate);
        profitCondition.setEndDate(endDate);
        return profitRepositoryService.list(profitCondition);
    }

    /**
     * 订单 指定时间区间内的分润记录
     */
    public List<Profit> queryProfitByOrderIds(List<Long> orderId, String beginDate, String endDate) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setOrderIds(orderId);
        profitCondition.setBeginDate(beginDate);
        profitCondition.setEndDate(endDate);
        return profitRepositoryService.list(profitCondition);
    }

    /**
     * 订单 指定时间区间内的分润记录
     * lig add 2024-02-27
     */
    public List<Profit> queryProfitByOrderIds(List<Long> orderId) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setOrderIds(orderId);
        return profitRepositoryService.list(profitCondition);
    }

    /**
     * 订单 指定时间区间内的分润记录
     */
    public List<Profit> queryProfitByShopId(Long shopId, String beginDate, String endDate) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setShopId(shopId);
        profitCondition.setBeginDate(beginDate);
        profitCondition.setEndDate(endDate);
        return profitRepositoryService.list(profitCondition);
    }

    public List<Profit> queryProfit(String beginDate, String endDate) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setBeginDate(beginDate);
        profitCondition.setEndDate(endDate);
        return profitRepositoryService.list(profitCondition);
    }

    /**
     * 订单 获取分润
     */
    public List<Profit> queryProfitByOrderId(Long orderId) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setOrderId(orderId);
        return profitRepositoryService.list(profitCondition);
    }

    public Profit queryProfitByOrderIdAndType(Long orderId, int orderType) {
        ProfitCondition profitCondition = new ProfitCondition();
        profitCondition.setOrderId(orderId);
        profitCondition.setOrderType(orderType);
        return profitRepositoryService.getProfit(profitCondition);
    }

    public Map<Long, Profit> groupById(List<Profit> profits) {
        return profits.stream().collect(Collectors.toMap(Profit::getId, Function.identity()));
    }

    /**
     * @description: 获取加钟订单比例
     * @author: lig
     * @date: 2024/3/28
     */
    private Double getExtRatio(List<Rule> ruleList, int serial) {
        List<Rule> tempRuleList = ruleList.stream().filter(f -> f.getSerial().equals(serial)).toList();
        if (CollUtil.isNotEmpty(tempRuleList)) {
            return Convert.toDouble(tempRuleList.get(0).getVal());
        } else {
            List<Rule> sortRuleList = ruleList.stream().sorted(Comparator.comparingInt(Rule::getSerial).reversed()).toList();
            if (CollUtil.isNotEmpty(sortRuleList)) {
                return Convert.toDouble(sortRuleList.get(0).getVal());
            }
        }
        return 0d;
    }


    /**
     * @description: 构造技师分润
     * @author: lig
     * @date: 2024/3/29
     */
    private void addMassagistRuleProfit(OrderInfo orderInfo) {
        //获取技师规则
        RuleCondition massagistRuleCondition = new RuleCondition();
        massagistRuleCondition.setRelevanceId(orderInfo.getMassagistId());
        massagistRuleCondition.setClassify(RuleClassifyEnum.$10.getCode());
        List<Rule> massagistRuleList = ruleService.listRule(massagistRuleCondition);
        //获取门店的规则
        RuleCondition shopRuleCondition = new RuleCondition();
        shopRuleCondition.setRelevanceId(orderInfo.getShopId());
        shopRuleCondition.setClassify(RuleClassifyEnum.$20.getCode());
        List<Rule> shopRuleList = ruleService.listRule(shopRuleCondition);
        //未知情况下设置兜底的门店和技师规则
        if (CollUtil.isEmpty(massagistRuleList) || CollUtil.isEmpty(shopRuleList)) {
            log.error("未设置门店、技师规则走兜底方案，订单Id：{}", orderInfo.getId());
            //门店兜底规则
            shopRuleList = Shop.defaultRule();
            //技师兜底规则
            massagistRuleList = Massagist.defaultRule();
        }
        //订单分润
        addOrderProfitPo(buildProfitPo(orderInfo), massagistRuleList, shopRuleList, orderInfo);
        List<OrderExt> orderExtList = orderInfo.getOrderExtList();
        if (CollUtil.isNotEmpty(orderExtList)) {
            orderExtList = orderInfo.getOrderExtList().stream().sorted(Comparator.comparing(OrderExt::getStartTime)).toList();
            for (int i = 0; i < orderExtList.size(); i++) {
                //加钟订单分润
                addExtOrderProfitPo(buildProfitPo(orderInfo), massagistRuleList, shopRuleList, orderInfo, i);
            }
        }
    }


    private ProfitPO buildProfitPo(OrderInfo orderInfo) {
        ProfitPO po = new ProfitPO();
        po.setOrderId(orderInfo.getId());
        po.setShopId(orderInfo.getShopId());
        po.setMassagistId(orderInfo.getMassagistId());
        po.setTravelPrice(orderInfo.getTravelPrice());
        po.setCreateBy(SessionUtil.getUser().getExtUserId());
        po.setCreateTime(new Date());
        return po;
    }


    /**
     * 构造分润的值
     *
     * @param shopRation      设置的门店比例
     * @param massagistRation 设置的技师比例
     * @author: lig
     * @date: 2024/3/29
     */
    private void buildProfitVal(ProfitPO po, Integer price,int ticketPrice, Double massagistRation, Double shopRation, List<Rule> massagistRuleList, List<Rule> shopRuleList) {
        //分佣金额按照原价
        price = price + ticketPrice;
        //技师金额
        Integer massagistIncome = NumberUtil.mul(price, massagistRation).intValue();

        //门店比例 （设置的比例 - 技师的比例）
        Double shopPercent = NumberUtil.sub(shopRation, massagistRation);
        //门店金额
        Integer shopIncome = NumberUtil.mul(price, shopPercent).intValue();

        //平台抽成比例  （100 - 门店设置的比例）
        Double adminPercent = NumberUtil.sub(Convert.toDouble(1), shopRation);
        Integer adminIncome = NumberUtil.mul(price, adminPercent).intValue();
        //平台承担优惠券
        adminIncome = adminIncome - ticketPrice;

//        int difference = 0;
//        if (couponSwitch) {
//            if (ObjectUtil.isNotNull(orderInfo)) {
//                //先通过门店ID找到所在城市
//                Shop shop = shopService.getShopById(orderInfo.getShopId());
//                CitiesServed cities = shop.getCity();
//                Double basePrice = ObjectUtil.isNotNull(cities.getPrice()) && cities.getPrice()!=0 ? cities.getPrice() : STARTING_PRICE;
//                List<Coupon> coupons = couponService.getCouponsByOrderId(orderInfo.getId());
//                if (CollUtil.isNotEmpty(coupons)) {
//                    if (SourceEnum.byCode(coupons.get(0).getSource()) != null && Objects.requireNonNull(SourceEnum.byCode(coupons.get(0).getSource())).getCode() == 1) {
//                        //使用了团购券的订单，车费免除的 有平台补给技师
//                        int travelPrice = po.getTravelPrice();
//                        if (travelPrice <= 1) {
//                            difference = basePrice.intValue() * 2 - 1;
//                        } else {
//                            difference = basePrice.intValue() * 2;
//                        }
//                    }
//                }
//                po.setTravelPrice(po.getTravelPrice() + difference);
//            }
//        }
        //技师实际收入
        po.setMassagistIncome(massagistIncome);
        po.setShopIncome(shopIncome);
        po.setAdminIncome(adminIncome);

        ProfitRule profitRule = new ProfitRule();
        profitRule.setMassagistPercent(massagistRation);
        profitRule.setShopPercent(shopPercent);
        profitRule.setAdminPercent(adminPercent);
        profitRule.setMassagistRule(Rule.listRuleToDto(massagistRuleList));
        profitRule.setShopRule(Rule.listRuleToDto(shopRuleList));

        po.setRuleData(JSONUtil.toJsonStr(profitRule));
    }

    /**
     * 构造技师订单分润PO（订单）
     *
     * @author: lig
     * @date: 2024/3/28
     */
    private void addOrderProfitPo(ProfitPO po, List<Rule> ruleList, List<Rule> shopRuleList, OrderInfo orderInfo) {

        po.setOrderType(1);
        //技师订单规则
        List<Rule> massagistOrderRuleList = ruleList.stream().filter(f -> RuleFlagEnum.$10.getCode().equals(f.getFlag())).sorted(Comparator.comparing(Rule::getSerial)).toList();
        List<Rule> shopOrderRuleList = shopRuleList.stream().filter(f -> RuleFlagEnum.$10.getCode().equals(f.getFlag())).sorted(Comparator.comparing(Rule::getSerial)).toList();

        //如果使用了优惠券，并且该城市是需要平台独自承担的需要单独处理
        int ticketPrice = 0;
        UserTicket userTicket = orderInfo.getTicket();
        Long shopId = orderInfo.getShopId();
        if (ObjectUtil.isNotNull(userTicket) && sysConfigurationRepositoryService.getValueByKey(KeyConstant.SHOP_DISCOUNTLIST).contains(String.valueOf(shopId))) {
            ticketPrice = userTicket.getRmb();
        }
        //订单金额 - 车费
        Integer price = (orderInfo.getOrderPrice() - orderInfo.getTravelPrice());

        //获取技师规则比例
        Double massagistRation = ruleService.getRatio4Massagist(massagistOrderRuleList, orderInfo);

        //获取 门店 规则比例
        Double shopRation = ruleService.getRatio4Shop(shopOrderRuleList, orderInfo);

        buildProfitVal(po, price, ticketPrice, massagistRation, shopRation, massagistOrderRuleList, shopOrderRuleList);

        profitRepositoryService.add(po);
    }

    /**
     * 构造技师订单分润PO（加钟）
     *
     * @param index
     * @author: lig
     * @date: 2024/3/28
     */
    private void addExtOrderProfitPo(ProfitPO po, List<Rule> ruleList, List<Rule> shopRuleList, OrderInfo orderInfo, Integer index) {

        po.setTravelPrice(null);
        po.setOrderType(2);
        List<Rule>  massagistOrderRuleList = ruleList.stream().filter(f -> RuleFlagEnum.$20.getCode().equals(f.getFlag())).sorted(Comparator.comparing(Rule::getSerial)).toList();
        List<Rule> shopOrderRuleList = shopRuleList.stream().filter(f -> RuleFlagEnum.$20.getCode().equals(f.getFlag())).sorted(Comparator.comparing(Rule::getSerial)).toList();

        //加钟订单 排序
        List<OrderExt> orderExtList = orderInfo.getOrderExtList().stream().sorted(Comparator.comparing(OrderExt::getStartTime)).toList();
        OrderExt orderExt = orderExtList.get(index);
        int serial = index + 1;

        //技师加钟计算比例
        Double massagistRation = getExtRatio(massagistOrderRuleList, serial);
        //门店加钟计算比例
        Double shopRation = getExtRatio(shopOrderRuleList, serial);
        //订单金额
        Integer price = orderExt.getOrderPrice();

        po.setExtendOrderId(orderExt.getId());

        buildProfitVal(po, price, 0, massagistRation, shopRation, massagistOrderRuleList, shopOrderRuleList);

        profitRepositoryService.add(po);
    }

}
